package sun.scheduler.util.graph.algorithm.maxflow;

import sun.scheduler.util.graph.Edge;

/**
 * Represents the generic {@link Edge} data of the {@link ResidualGraph}
 *
 * @see ResidualEdgeData
 * @author mfj
 */
public class ResidualEdgeData
{

    /**
     * Indictaes wheter this edge is a forward edge.
     */
    public final boolean isForwardEdge;
    private double residualCapacity;
    private EdgeFlow edgeFlow;
    /**
     * Caches the edge in the other direction.
     */
    protected Edge<Label, ResidualEdgeData> other;

    /**
     * Instantaites a new instance of the {@link ResidualEdgeData} object which
     * is assoziated with the given {@link EdgeFlow} instance.
     *
     * @param isForwardEdge a boolean which indicates wheter this edge is a
     * forward egde
     * @param edgeFlow the {@link EdgeFlow} instance which defines the residual
     * capacities.
     */
    public ResidualEdgeData(boolean isForwardEdge, EdgeFlow edgeFlow)
    {
        this.isForwardEdge = isForwardEdge;
        this.edgeFlow = edgeFlow;
        this.residualCapacity = isForwardEdge ? forwardCapacity() : backwardCapacity();
    }

    /**
     * Increases the flow on forward edges and reduces the flow on backward
     * egdes. Sets residual capacities accordingly, which ios defined as flow -
     * lowercapacity for forward edges and uppercapacity - flow for backward
     * edges.
     *
     * @param val
     */
    public void augment(double val)
    {
        if (isForwardEdge)
        {
            edgeFlow.addFlow(val);
            residualCapacity = forwardCapacity();
            other.getData().residualCapacity = backwardCapacity();
        }
        else
        {
            edgeFlow.addFlow(-val);
            residualCapacity = backwardCapacity();
            other.getData().residualCapacity = backwardCapacity();
        }
    }

    private double backwardCapacity()
    {
        return edgeFlow.getFlow() - edgeFlow.getLowerCapacity();
    }

    private double forwardCapacity()
    {
        return edgeFlow.getUpperCapacity() - edgeFlow.getFlow();
    }

    /**
     * Gets the residual capacity.
     *
     * @return
     */
    public double getResidualCapacity()
    {
        return residualCapacity;
    }

    @Override
    public String toString()
    {
        return "rCap: " + residualCapacity + " " + (isForwardEdge ? "fo" : "ba")
                + " " + edgeFlow.getLowerCapacity() + " <= " + edgeFlow.getFlow() 
                + " <= " + edgeFlow.getUpperCapacity();
    }

}
